package com.zhiyou.app.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.github.binarywang.wxpay.bean.transfer.TransferBillsRequest;
import com.github.binarywang.wxpay.bean.transfer.TransferBillsResult;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.pagehelper.PageInfo;
import com.github.pagehelper.page.PageMethod;
import com.zhiyou.app.common.constant.CommonPageUtil;
import com.zhiyou.app.common.constant.UserHandler;
import com.zhiyou.app.common.exception.BizException;
import com.zhiyou.app.common.util.GenerateNumUtil;
import com.zhiyou.app.pojo.entity.UserEntity;
import com.zhiyou.app.pojo.entity.UserWalletEntity;
import com.zhiyou.app.mapper.UserWalletMapper;
import com.zhiyou.app.pojo.entity.WithdrawalHistoryEntity;
import com.zhiyou.app.pojo.enums.NumTypeEnum;
import com.zhiyou.app.pojo.enums.WithdrawalStatusEnum;
import com.zhiyou.app.pojo.vo.UserWalletVo;
import com.zhiyou.app.pojo.vo.WithdrawalListQueryRequestVo;
import com.zhiyou.app.pojo.vo.WithdrawalListResponseVo;
import com.zhiyou.app.pojo.vo.WithdrawalResponseVo;
import com.zhiyou.app.service.IUserService;
import com.zhiyou.app.service.IUserWalletService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zhiyou.app.service.IWithdrawalHistoryService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;

import javax.annotation.Resource;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author jonathan.z
 * @since 2025-07-03
 */
@Service
public class UserWalletServiceImpl extends ServiceImpl<UserWalletMapper, UserWalletEntity> implements IUserWalletService {
    @Value("${wallet.withdrawal.min:1000}")
    private Integer withdrawalMin;
    @Resource
    private IWithdrawalHistoryService withdrawalHistoryService;
    @Resource
    private PlatformTransactionManager transactionManager;
    @Resource
    private IUserService userService;
    @Resource
    private WxPayService wxPayService;
    @Value("${wx.pay.notifyUrl}")
    private String notifyUrl;
    @Value("${wx.pay.transferSceneId}")
    private String transferSceneId;

    @Override
    public WithdrawalResponseVo withdrawal(Integer amount) {
        UserWalletEntity one = withdrawalCheck(amount);
        WithdrawalHistoryEntity withdrawalHistoryEntity = new WithdrawalHistoryEntity();
        if (one.getWithdrawableAmount() >= amount) {
            TransactionDefinition def = new DefaultTransactionDefinition();
            TransactionStatus status = transactionManager.getTransaction(def);
            String withdrawalNum = GenerateNumUtil.generateNum(NumTypeEnum.DRA);
            try {
                withdrawalHistoryEntity.setUserId(UserHandler.getLoginUser().getUserId())
                        .setUserWalletId(one.getId())
                        .setAmount(amount)
                        .setStatus(WithdrawalStatusEnum.CREATE)
                        .setContent("提现【" + amount / 100 + "】申请")
                        .setOutWithdrawalNum(withdrawalNum);
                withdrawalHistoryService.save(withdrawalHistoryEntity);
                update(new LambdaUpdateWrapper<UserWalletEntity>().eq(UserWalletEntity::getId, one.getId()).setSql("freeze_amount = freeze_amount+" + amount)
                        .setSql("withdrawable_amount=withdrawable_amount-" + amount));
                transactionManager.commit(status);
            } catch (Exception ex) {
                // Rollback transaction
                transactionManager.rollback(status);
                log.error("保存提现记录失败", ex);
                throw new BizException("保存提现记录失败", ex.getMessage());
            }
            return getWxWithdrawalResponseVo(amount, withdrawalNum, withdrawalHistoryEntity);
        }
        throw new BizException("当前账户不足最低提现金额[" + withdrawalMin / 100 + "]");
    }

    private UserWalletEntity withdrawalCheck(Integer amount) {
        UserWalletEntity one = getOne(new LambdaQueryWrapper<UserWalletEntity>().eq(UserWalletEntity::getUserId, UserHandler.getLoginUser().getUserId()));
        UserWalletVo userWalletVo = parseWalletVo(one);
        one.setWithdrawableAmount(userWalletVo.getWithdrawableAmount());
        one.setFreezeAmount(userWalletVo.getFreezeAmount());
        if (one.getTotalAmount() < withdrawalMin) {
            throw new BizException("当前账户提现金额不足,最小提现金额[" + Float.valueOf(withdrawalMin) / 100 + "元]");
        } else if (amount < withdrawalMin) {
            throw new BizException("最小提现金额[" + Float.valueOf(withdrawalMin) / 100 + "元]");
        }
        return one;
    }

    private WithdrawalResponseVo getWxWithdrawalResponseVo(Integer amount, String withdrawalNum, WithdrawalHistoryEntity withdrawalHistoryEntity) {
        try {
            UserEntity user = userService.getById(UserHandler.getLoginUser().getUserId());
            List<TransferBillsRequest.TransferSceneReportInfo> list = Arrays.asList(TransferBillsRequest.TransferSceneReportInfo.newBuilder()
                    .infoType("岗位类型")
                    .infoContent("平台用户")
                    .build(), TransferBillsRequest.TransferSceneReportInfo.newBuilder()
                    .infoType("报酬说明")
                    .infoContent("邀请用户佣金提现")
                    .build());
            TransferBillsResult result = wxPayService.getTransferService().transferBills(TransferBillsRequest.newBuilder()
                    .openid(user.getOpenId())
                    .outBillNo(withdrawalNum)
                    .appid(wxPayService.getConfig().getAppId())
                    .transferAmount(amount)
                    .transferRemark("账户[" + user.getId() + "]提现")
                    .transferSceneId(transferSceneId)
                    .notifyUrl(notifyUrl)
                    .transferSceneReportInfos(list)
                    .build());
            switch (WithdrawalStatusEnum.parse(result.getState())) {
                case SUCCESS:
                    withdrawalHistoryEntity.setStatus(WithdrawalStatusEnum.parse(result.getState()));
                    withdrawalHistoryService.save(withdrawalHistoryEntity);
                    update(new LambdaUpdateWrapper<UserWalletEntity>().eq(UserWalletEntity::getUserId, UserHandler.getLoginUser().getUserId())
                            .setSql("total_amount = total_amount -" + amount));
                    break;
                case FAIL:
                    withdrawalHistoryEntity.setStatus(WithdrawalStatusEnum.FAIL).setContent(result.getFailReason());
                    withdrawalHistoryService.updateById(withdrawalHistoryEntity);
                    break;
                case CANCELING:
                    withdrawalHistoryEntity.setStatus(WithdrawalStatusEnum.CANCELLED);
                    withdrawalHistoryService.updateById(withdrawalHistoryEntity);
                    break;
                case CANCELLED:
                    withdrawalHistoryEntity.setStatus(WithdrawalStatusEnum.CANCELLED);
                    withdrawalHistoryService.updateById(withdrawalHistoryEntity);
                    break;
                case PROCESSING:
                    withdrawalHistoryEntity.setStatus(WithdrawalStatusEnum.PROCESSING);
                    withdrawalHistoryService.updateById(withdrawalHistoryEntity);
                    break;
                case WAIT_USER_CONFIRM:
                    withdrawalHistoryEntity.setStatus(WithdrawalStatusEnum.WAIT_USER_CONFIRM);
                    withdrawalHistoryService.updateById(withdrawalHistoryEntity);
                    break;
                case TRANSFERING:
                    withdrawalHistoryEntity.setStatus(WithdrawalStatusEnum.TRANSFERING);
                    withdrawalHistoryService.updateById(withdrawalHistoryEntity);
                    break;
                case ACCEPTED:
                    withdrawalHistoryEntity.setStatus(WithdrawalStatusEnum.ACCEPTED);
                    withdrawalHistoryService.updateById(withdrawalHistoryEntity);
                    break;
                default:
                    throw new BizException("未知的提现状态");
            }
            return new WithdrawalResponseVo().setAppId(wxPayService.getConfig().getAppId())
                    .setMchId(wxPayService.getConfig().getMchId())
                    .setPackageInfo(result.getPackageInfo());
        } catch (Exception ex) {
            // Rollback transaction
            withdrawalHistoryService.updateById(withdrawalHistoryEntity.setStatus(WithdrawalStatusEnum.FAIL).setContent(ex.getMessage()));
            log.error("保存提现记录失败", ex);
            throw new BizException("保存提现记录失败", ex.getMessage());
        }
    }


    @Override
    public WithdrawalResponseVo reWithdrawal(Integer withdrawalId) {
        WithdrawalHistoryEntity byId = withdrawalHistoryService.getById(withdrawalId);
        if (byId != null) {
            withdrawalCheck(byId.getAmount());
            return getWxWithdrawalResponseVo(byId.getAmount(), byId.getOutWithdrawalNum(), byId);
        }
        throw new BizException("提现订单不存在");
    }

    @Override
    public void addAmount(Integer amount, Integer userId) {
        update(new LambdaUpdateWrapper<UserWalletEntity>().eq(UserWalletEntity::getUserId, userId)
                .setSql("total_amount = total_amount " + amount));
    }

    @Override
    public PageInfo<WithdrawalListResponseVo> queryWithdrawalList(WithdrawalListQueryRequestVo withdrawalListQueryRequestVo) {
        PageMethod.startPage(withdrawalListQueryRequestVo.getPageNum(), withdrawalListQueryRequestVo.getPageSize());
        LambdaQueryWrapper<WithdrawalHistoryEntity> eq = new LambdaQueryWrapper<WithdrawalHistoryEntity>();
        if (withdrawalListQueryRequestVo.getUserId() != null) {
            eq.eq(WithdrawalHistoryEntity::getUserId, withdrawalListQueryRequestVo.getUserId());
        }
        if (withdrawalListQueryRequestVo.getStartTime() != null) {
            eq.ge(WithdrawalHistoryEntity::getCreateTime, withdrawalListQueryRequestVo.getStartTime());
        }
        if (withdrawalListQueryRequestVo.getEndTime() != null) {
            eq.le(WithdrawalHistoryEntity::getCreateTime, withdrawalListQueryRequestVo.getEndTime());
        }
        if (withdrawalListQueryRequestVo.getStatus() != null) {
            eq.eq(WithdrawalHistoryEntity::getStatus, withdrawalListQueryRequestVo.getStatus());
        }
        List<WithdrawalHistoryEntity> list = withdrawalHistoryService.list(eq.orderByDesc(WithdrawalHistoryEntity::getCreateTime));
        return CommonPageUtil.pageCovert(list, list.stream().map(t -> {
            WithdrawalListResponseVo responseVo = new WithdrawalListResponseVo();
            BeanUtils.copyProperties(t, responseVo);
            responseVo.setUserInfo(userService.getProfile(t.getUserId()));
            return responseVo;
        }).collect(Collectors.toList()));
    }

    @Override
    public UserWalletVo parseWalletVo(UserWalletEntity userWalletEntity) {
        Integer withdrawalAmount = userWalletEntity.getTotalAmount() > withdrawalMin ? userWalletEntity.getTotalAmount() : 0;
        userWalletEntity.setFreezeAmount(userWalletEntity.getFreezeAmount());
        userWalletEntity.setWithdrawableAmount(withdrawalAmount);
        updateById(userWalletEntity);
        return new UserWalletVo().setTotalAmount(userWalletEntity.getTotalAmount())
                .setFreezeAmount(userWalletEntity.getFreezeAmount())
                .setWithdrawableAmount(userWalletEntity.getWithdrawableAmount())
                .setWalletId(userWalletEntity.getId());
    }
}
